#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include "platform_data_special.h"
#include "stm32mp157xxx.h"
#include <linux/i2c.h>
#define TEMPE _IOR('T',0X1234,unsigned long)
#define HUMI _IOR('H',0X1235,unsigned long)

struct stm32mp157a{
	unsigned int major;
	struct resource *resource[5];
	struct class *cls;
	struct device *dev;
	unsigned int gpio_count;
	struct gpio_desc **get_gpios;
	struct Platform_data_spex *spex;
	struct i2c_client *client;
};
struct stm32mp157a *drv_led;
int drv_led_open(struct inode *ide, struct file *filp)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	
	return ret;
}
	
int drv_led_close(struct inode *ide, struct file *filp)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	return ret;
}
ssize_t drv_led_write(struct file *flp, const char __user *buf, size_t size , loff_t *flag)
{
	int ret =0;
	int led_status=0;
	int i;
	printk("---%s---\r\n",__FUNCTION__);
	ret = copy_from_user(&led_status, buf, size);
	if(ret !=0)
	{
		printk("copy_from_user_err\r\n");
		return ret;
	}
	if(led_status == 0)	
	{
		for(i=0;i<drv_led->gpio_count;i++)
		{	
			gpiod_set_value(drv_led->get_gpios[i],0);
		}
	}
	else
	{
		for(i=0;i<drv_led->gpio_count;i++)
		{	
			gpiod_set_value(drv_led->get_gpios[i],1);
		}
	}
	return ret;
}
long drv_iic_ioctl(struct file *flp, unsigned int cmd, unsigned long data)
{
	long ret =0;
	u16 read_data=0;
	printk("---%s---\r\n",__FUNCTION__);
	switch(cmd)
	{
		case TEMPE:
				read_data = i2c_smbus_read_word_data(drv_led->client,0xe3);
				printk("TEMPE=0x%x\r\n",read_data);
			break;
		case HUMI:
				read_data = i2c_smbus_read_word_data(drv_led->client,0xe5);
				printk("HUMIY=0x%x\r\n",read_data);
			break;
		default:
				printk("NOT CMD\r\n");
			break;

	}
	ret = copy_to_user((void __user *)data, &read_data, sizeof(read_data));
	if(ret < 0)
	{
		printk("copy_to_user_err\r\n");
		return ret;
	}
	return ret;
}

const struct file_operations fops={
	.open = drv_led_open,
	.release = drv_led_close,
	.write = drv_led_write,
	.unlocked_ioctl = drv_iic_ioctl,
};

int drv_iic_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int ret =0;
	//int i=0;
	//char name_string[10];
	printk("---%s---\r\n",__FUNCTION__);

	//实例化一个对象
	drv_led= kzalloc(sizeof(struct stm32mp157a), GFP_KERNEL);
	if(IS_ERR(drv_led))
	{
		printk("kzalloc_err\r\n");
		ret = PTR_ERR(drv_led);
		return ret;
	}
	drv_led->spex = kzalloc(sizeof(struct Platform_data_spex), GFP_KERNEL);
	if(IS_ERR(drv_led->spex))
	{
		printk("spex_kzalloc_err\r\n");
		ret = PTR_ERR(drv_led->spex);
		goto spex_kzalloc_err;
	}
	of_property_read_u32_index(client->dev.of_node, "minum", 0, &drv_led->spex->minum);
	of_property_read_string(client->dev.of_node, "dev_name", &drv_led->spex->name);
	printk("minum=%d name=%s\r\n",drv_led->spex->minum,drv_led->spex->name);


	//申请设备号
	drv_led->major = register_chrdev(0, drv_led->spex->name, &fops);
	if(drv_led->major < 0)
	{
		printk("register_chrdev_err\r\n");
		goto register_chrdev_err;
	}
	printk("major=%d \r\n",drv_led->major);
	//创建类
	drv_led->cls = class_create(THIS_MODULE, drv_led->spex->name);
	if(IS_ERR(drv_led->cls))
	{
		printk("class_create_err\r\n");
		ret = PTR_ERR(drv_led->cls);
		goto class_create_err;
	}
	//创建节点
	drv_led->dev = device_create(drv_led->cls, NULL, MKDEV(drv_led->major, drv_led->spex->minum), NULL, drv_led->spex->name);
	if(IS_ERR(drv_led->dev))
	{
		printk("device_create_err\r\n");
		ret = PTR_ERR(drv_led->dev);
		goto device_create_err;
	}
	drv_led->client = client;
	return ret;
#if 0

	//硬件初始化
	//获取GPIO数量
	drv_led->gpio_count = gpiod_count(&pdev->dev,"led");
	if(drv_led->gpio_count < 0)
	{
		printk("of_gpio_count_err\r\n");
		ret = drv_led->gpio_count;
		goto of_gpio_count_err;
	}
	printk("gpio_count=%d\r\n",drv_led->gpio_count);
	//获取gpio标号
	drv_led->get_gpios = kzalloc(sizeof(struct gpio_desc *)*drv_led->gpio_count,GFP_KERNEL);
	if(IS_ERR(drv_led->get_gpios))
	{
		printk("get_gpios_kzalloc_err\r\n");
		ret = PTR_ERR(drv_led->get_gpios);
		goto get_gpios_kzalloc_err;
	}
	for(i=0;i<drv_led->gpio_count;i++)
	{
		//drv_led->get_gpios[i] = gpiod_get_index(&pdev->dev, "led",i, GPIOD_OUT_LOW);
		drv_led->get_gpios[i] = devm_gpiod_get_index(&pdev->dev, "led",i, GPIOD_OUT_LOW);//带资源管理的接口函数，用此函数获取标号不需要手动释放使用权
		gpiod_direction_output(drv_led->get_gpios[i],0);
	}
	return ret;	
get_gpios_kzalloc_err:

of_gpio_count_err:
	device_destroy(drv_led->cls, MKDEV(drv_led->major, drv_led->spex->minum));
#endif
device_create_err:
	class_destroy(drv_led->cls );
class_create_err:
	unregister_chrdev(drv_led->major,drv_led->spex->name);
register_chrdev_err:
	kfree(drv_led->spex);
spex_kzalloc_err:
	kfree(drv_led);

	return ret;

}
int drv_iic_remove(struct i2c_client *client)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	
#if 0
	kfree(drv_led->get_gpios);
#endif

	device_destroy(drv_led->cls, MKDEV(drv_led->major, drv_led->spex->minum));
	class_destroy(drv_led->cls );
	unregister_chrdev(drv_led->major,drv_led->spex->name);
	
	kfree(drv_led->spex);
	kfree(drv_led);

	return ret;
}


const struct of_device_id iic_table[]={
	{ .compatible = "stm32mp157,i2c_si7006" },
};
struct i2c_driver drv={
	.probe = drv_iic_probe,
	.remove = drv_iic_remove,
	.driver = {
		.name = "iic_si7006",
		.of_match_table = iic_table,
	}, 
};

static int __init drv_iic_init(void)
{
	int ret =0;
	printk("---%s---\r\n",__FUNCTION__);
	i2c_add_driver(&drv);
	return ret;
}
void __exit drv_iic_exit(void)
{
	printk("---%s---\r\n",__FUNCTION__);
	i2c_del_driver(&drv);
}

module_init(drv_iic_init);
module_exit(drv_iic_exit);
MODULE_LICENSE("GPL");

